import { _decorator, Component, Node, view, UITransform, Vec3, math, EventHandler, Graphics, Color, TweenEasing, Enum } from 'cc';
const { ccclass, property } = _decorator;

// 定义缓动类型枚举
export enum EasingType {
    linear = 'linear',
    smooth = 'smooth',
    fade = 'fade',
    quadIn = 'quadIn',
    quadOut = 'quadOut',
    quadInOut = 'quadInOut',
    quadOutIn = 'quadOutIn',
    cubicIn = 'cubicIn',
    cubicOut = 'cubicOut',
    cubicInOut = 'cubicInOut',
    cubicOutIn = 'cubicOutIn',
    quartIn = 'quartIn',
    quartOut = 'quartOut',
    quartInOut = 'quartInOut',
    quartOutIn = 'quartOutIn',
    quintIn = 'quintIn',
    quintOut = 'quintOut',
    quintInOut = 'quintInOut',
    quintOutIn = 'quintOutIn',
    sineIn = 'sineIn',
    sineOut = 'sineOut',
    sineInOut = 'sineInOut',
    sineOutIn = 'sineOutIn',
    expoIn = 'expoIn',
    expoOut = 'expoOut',
    expoInOut = 'expoInOut',
    expoOutIn = 'expoOutIn',
    circIn = 'circIn',
    circOut = 'circOut',
    circInOut = 'circInOut',
    circOutIn = 'circOutIn',
    elasticIn = 'elasticIn',
    elasticOut = 'elasticOut',
    elasticInOut = 'elasticInOut',
    elasticOutIn = 'elasticOutIn',
    backIn = 'backIn',
    backOut = 'backOut',
    backInOut = 'backInOut',
    backOutIn = 'backOutIn',
    bounceIn = 'bounceIn',
    bounceOut = 'bounceOut',
    bounceInOut = 'bounceInOut',
    bounceOutIn = 'bounceOutIn',
}

export enum ControlPointSideType {
    Left = 1,
    Right = -1,
    Random = 0,
}

@ccclass('BezierMove')
export class BezierMove extends Component {
    @property({ displayName: '速度' })
    speed: number = 600; // 移动速度，单位：像素/秒

    @property({ displayName: '控制点方向', tooltip: '0=随机, 1=左侧，-1=右侧（相对于从起点到终点的方向）' })
    controlPointSide: ControlPointSideType = ControlPointSideType.Left; // 控制点位置：0=随机，1=左侧，-1=右侧（相对于从起点到终点的方向）

    @property({ displayName: '控制点偏移系数', tooltip: '0~1之间,控制点偏移系数,值越大曲线越弯曲' })
    controlPointOffset: number = 0.5; // 控制点偏移系数，值越大曲线越弯曲

    @property({ displayName: '控制点随机性', tooltip: '0~1之间,控制点随机性,值越大随机性越强' })
    controlPointRandomness: number = 0.3; // 控制点随机性，值越大随机性越强

    @property({ displayName: '自动旋转' })
    autoRotate: boolean = true; // 是否自动旋转以面向移动方向

    @property({ displayName: '显示轨迹' })
    showTrajectory: boolean = true; // 是否显示移动轨迹

    @property({ displayName: '轨迹颜色' })
    trajectoryColor: Color = new Color(0, 255, 0, 255); // 轨迹颜色，默认绿色

    @property({ displayName: '轨迹宽度' })
    trajectoryWidth: number = 3; // 轨迹宽度

    @property({ displayName: '缓动函数', type: Enum(EasingType) })
    easing: TweenEasing = EasingType.linear; // 缓动效果类型，默认为线性

    @property({ displayName: '角度平滑系数', tooltip: '0~1之间,值越小旋转越平滑,0表示不旋转,1表示立即旋转' })
    rotationSmoothness: number = 0.6; // 角度平滑系数，值越小旋转越平滑

    private _graphics: Graphics | null = null; // Graphics组件引用
    private _currentAngle: number = 0; // 当前角度

    private _startPoint: Vec3 = new Vec3();
    private _endPoint: Vec3 = new Vec3();
    private _controlPoint: Vec3 = new Vec3();
    private _t: number = 0; // Bezier曲线参数 (0 到 1)
    private _totalTime: number = 0; // 完成当前曲线所需的时间
    private _isMoving: boolean = false; // 是否正在移动
    private _moveEndCallback: Function = null; // 移动完成回调函数
    private _moveEndTarget: any; // 移动完成回调函数的目标对象
    private _moveStartCallback: Function = null; // 移动开始回调函数, (totalTime: number) => void
    private _moveStartTarget: any; // 移动开始回调函数的目标对象

    onEnable() {
        this._startPoint.set(this.node.position);
        this._currentAngle = this.node.angle;

        this._initGraphics();
    }

    onDisable() {
        if (this._graphics) {
            this._graphics.clear();
            if (this._graphics.node && this._graphics.node.isValid) {
                const uniqueNodeName = `TrajectoryGraphics_${this.node.uuid}`;
                this._graphics.node.destroy();
            }
        }
    }

    onMoveComplete(callback: Function, target: any) {
        this._moveEndCallback = callback;
        this._moveEndTarget = target;
    }

    onMoveStart(callback: Function, target: any) {
        this._moveStartCallback = callback;
        this._moveStartTarget = target;
    }


    update(deltaTime: number) {
        if (!this._isMoving || this._totalTime <= 0) return; // 如果没有移动或路径生成失败，则返回

        // 更新进度
        this._t += deltaTime / this._totalTime;

        // 应用缓动效果
        let easedT = this._applyEasing(this._t);

        if (this._t >= 1.0) {
            // 到达终点
            this.node.setPosition(this._endPoint);
            this._isMoving = false;

            this._moveEndCallback && this._moveEndCallback.apply(this._moveEndTarget);
            // 清除轨迹
            if (this.showTrajectory && this._graphics) {
                this._graphics.clear();
                if (this._graphics.node.parent !== this.node) {
                    const graphicsNode = this._graphics.node;
                    if (graphicsNode.parent) {
                        graphicsNode.removeFromParent();
                    }
                    this.node.addChild(graphicsNode);
                }
            }
        } else {
            const currentPos = this._calculateQuadraticBezierPoint(easedT, this._startPoint, this._controlPoint, this._endPoint);
            this.node.setPosition(currentPos);

            if (this.autoRotate) {
                const tangent = this._calculateQuadraticBezierTangent(easedT, this._startPoint, this._controlPoint, this._endPoint);
                if (tangent.lengthSqr() > 0.001) { 
                    // 避免除以零或NaN角度
                    const targetAngle = math.toDegree(Math.atan2(tangent.y, tangent.x)) - 90;

                    // 使用平滑插值方法计算新角度
                    this._currentAngle = this._smoothAngle(this._currentAngle, targetAngle, this.rotationSmoothness);
                    this.node.angle = this._currentAngle;
                }
            }
        }
    }

    /**
     * 移动到指定位置
     * @param targetPos 目标位置
     */
    public moveTo(targetPos: Vec3): void {
        this._startPoint.set(this.node.position);
        this._endPoint.set(targetPos);

        this._currentAngle = this.node.angle;

        this._generateControlPoint();

        const approxLength = Vec3.distance(this._startPoint, this._controlPoint) + Vec3.distance(this._controlPoint, this._endPoint);
        this._totalTime = approxLength / this.speed;
        if (this._totalTime < 0.1) { // 确保最小持续时间
            this._totalTime = 0.1;
        }

        if (this.showTrajectory) {
            this._drawTrajectory();
        }

        this._t = 0;
        this._isMoving = true;

        this._moveStartCallback && this._moveStartCallback.apply(this._moveStartTarget, [this._totalTime]);
    }

    /**
     * 自动生成控制点
     */
    private _generateControlPoint(): void {
        const midPoint = new Vec3();
        Vec3.lerp(midPoint, this._startPoint, this._endPoint, 0.5);

        const direction = new Vec3();
        Vec3.subtract(direction, this._endPoint, this._startPoint);

        const perpendicular = new Vec3(-direction.y, direction.x, 0);
        Vec3.normalize(perpendicular, perpendicular);

        let sideMultiplier = 1;
        if (this.controlPointSide === ControlPointSideType.Random) {
            sideMultiplier = Math.random() < 0.5 ? 1 : -1;
        } else {
            sideMultiplier = this.controlPointSide;
        }

        // 根据控制点偏移系数和随机性计算控制点
        const distance = Vec3.distance(this._startPoint, this._endPoint);
        const offset = distance * this.controlPointOffset;
        const randomFactor = (Math.random() * 2 - 1) * this.controlPointRandomness;

        // 设置控制点 = 中点 + 垂直向量 * 偏移 * (1 + 随机因子) * 侧面乘数
        this._controlPoint.set(
            midPoint.x + perpendicular.x * offset * (1 + randomFactor) * sideMultiplier,
            midPoint.y + perpendicular.y * offset * (1 + randomFactor) * sideMultiplier,
            0
        );
    }

    /**
     * 停止当前移动
     */
    stopMoving(): void {
        this._isMoving = false;
    }

    /**
     * 计算二次贝塞尔曲线上的点
     */
    private _calculateQuadraticBezierPoint(t: number, p0: Vec3, p1: Vec3, p2: Vec3): Vec3 {
        const u = 1 - t;
        const tt = t * t;
        const uu = u * u;

        const p = new Vec3();
        // p = (u^2 * p0) + (2 * u * t * p1) + (t^2 * p2)
        Vec3.multiplyScalar(p, p0, uu);
        const temp1 = new Vec3();
        Vec3.multiplyScalar(temp1, p1, 2 * u * t);
        Vec3.add(p, p, temp1);
        const temp2 = new Vec3();
        Vec3.multiplyScalar(temp2, p2, tt);
        Vec3.add(p, p, temp2);

        return p;
    }

    /**
     * 计算二次贝塞尔曲线的切线（导数）
     */
    private _calculateQuadraticBezierTangent(t: number, p0: Vec3, p1: Vec3, p2: Vec3): Vec3 {

        const u = 1 - t;
        const tangent = new Vec3();

        // tangent = 2 * (1 - t) * (p1 - p0) + 2 * t * (p2 - p1)
        const term1 = new Vec3();
        Vec3.subtract(term1, p1, p0);
        Vec3.multiplyScalar(term1, term1, 2 * u);

        const term2 = new Vec3();
        Vec3.subtract(term2, p2, p1);
        Vec3.multiplyScalar(term2, term2, 2 * t);

        Vec3.add(tangent, term1, term2);

        return tangent;
    }

    /**
     * 应用缓动效果到t值
     * @param t 原始t值（0-1之间）
     * @returns 应用缓动后的t值
     */
    private _applyEasing(t: number): number {
        // 确保t在0-1范围内
        t = Math.max(0, Math.min(1, t));

        // 使用tween.easing函数应用缓动
        switch (this.easing) {
            case EasingType.linear:
                return t; // 线性不需要额外处理
            case EasingType.smooth:
                return t * t * (3 - 2 * t); // 平滑过渡
            case EasingType.fade:
                return t * t * (3 - 2 * t); // 平滑过渡
            case EasingType.quadIn:
                return t * t; // 二次方加速
            case EasingType.quadOut:
                return t * (2 - t); // 二次方减速
            case EasingType.quadInOut:
                return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t; // 二次方加速然后减速
            case EasingType.quadOutIn:
                return t < 0.5 ? 0.5 * (1 - Math.pow(-2 * t + 1, 2)) : 0.5 * Math.pow(2 * t - 1, 2) + 0.5; // 二次方减速然后加速
            case EasingType.cubicIn:
                return t * t * t; // 三次方加速
            case EasingType.cubicOut:
                return (--t) * t * t + 1; // 三次方减速
            case EasingType.cubicInOut:
                return t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1; // 三次方加速然后减速
            case EasingType.cubicOutIn:
                return t < 0.5 ? 0.5 * ((t = t * 2 - 1) * t * t + 1) : 0.5 * (t = t * 2 - 1) * t * t + 0.5; // 三次方减速然后加速
            case EasingType.quartIn:
                return t * t * t * t; // 四次方加速
            case EasingType.quartOut:
                return 1 - (--t) * t * t * t; // 四次方减速
            case EasingType.quartInOut:
                return t < 0.5 ? 8 * t * t * t * t : 1 - 8 * (--t) * t * t * t; // 四次方加速然后减速
            case EasingType.quartOutIn:
                return t < 0.5 ? 0.5 * (1 - Math.pow(-2 * t + 1, 4)) : 0.5 * Math.pow(2 * t - 1, 4) + 0.5; // 四次方减速然后加速
            case EasingType.quintIn:
                return t * t * t * t * t; // 五次方加速
            case EasingType.quintOut:
                return 1 + (--t) * t * t * t * t; // 五次方减速
            case EasingType.quintInOut:
                return t < 0.5 ? 16 * t * t * t * t * t : 1 + 16 * (--t) * t * t * t * t; // 五次方加速然后减速
            case EasingType.quintOutIn:
                return t < 0.5 ? 0.5 * (1 - Math.pow(-2 * t + 1, 5)) : 0.5 * Math.pow(2 * t - 1, 5) + 0.5; // 五次方减速然后加速
            case EasingType.sineIn:
                return 1 - Math.cos(t * Math.PI / 2); // 正弦加速
            case EasingType.sineOut:
                return Math.sin(t * Math.PI / 2); // 正弦减速
            case EasingType.sineInOut:
                return 0.5 * (1 - Math.cos(Math.PI * t)); // 正弦加速然后减速
            case EasingType.sineOutIn:
                return t < 0.5 ? 0.5 * Math.sin(t * Math.PI) : 0.5 - 0.5 * Math.cos((t * 2 - 1) * Math.PI / 2); // 正弦减速然后加速
            case EasingType.circIn:
                return 1 - Math.sqrt(1 - t * t); // 圆形加速
            case EasingType.circOut:
                return Math.sqrt(1 - (t - 1) * (t - 1)); // 圆形减速
            case EasingType.circInOut:
                return t < 0.5
                    ? (1 - Math.sqrt(1 - 4 * t * t)) / 2
                    : (Math.sqrt(1 - Math.pow(-2 * t + 2, 2)) + 1) / 2; // 圆形加速然后减速
            case EasingType.circOutIn:
                return t < 0.5 ? 0.5 * Math.sqrt(1 - Math.pow(-2 * t + 1, 2)) : 0.5 * (2 - Math.sqrt(1 - Math.pow(2 * t - 1, 2))); // 圆形减速然后加速
            case EasingType.expoIn:
                return t === 0 ? 0 : Math.pow(2, 10 * t - 10); // 指数加速
            case EasingType.expoOut:
                return t === 1 ? 1 : 1 - Math.pow(2, -10 * t); // 指数减速
            case EasingType.expoInOut:
                return t === 0 ? 0 : t === 1 ? 1 : t < 0.5
                    ? Math.pow(2, 20 * t - 10) / 2
                    : (2 - Math.pow(2, -20 * t + 10)) / 2; // 指数加速然后减速
            case EasingType.expoOutIn:
                return t === 0 ? 0 : t === 1 ? 1 : t < 0.5
                    ? 0.5 * (1 - Math.pow(2, -20 * t))
                    : 0.5 * Math.pow(2, 20 * (t - 0.5) - 10) + 0.5; // 指数减速然后加速
            case EasingType.backIn:
                const s = 1.70158;
                return t * t * ((s + 1) * t - s); // 回弹加速
            case EasingType.backOut:
                const s2 = 1.70158;
                return (t = t - 1) * t * ((s2 + 1) * t + s2) + 1; // 回弹减速
            case EasingType.backInOut:
                const s3 = 1.70158 * 1.525;
                if (t < 0.5) {
                    return (t * 2) * (t * 2) * ((s3 + 1) * (t * 2) - s3) / 2;
                } else {
                    return ((t * 2 - 2) * (t * 2 - 2) * ((s3 + 1) * (t * 2 - 2) + s3) + 2) / 2;
                } // 回弹加速然后减速
            case EasingType.backOutIn:
                const s4 = 1.70158;
                return t < 0.5
                    ? 0.5 * ((t = t * 2 - 1) * t * ((s4 + 1) * t + s4) + 1)
                    : 0.5 * (t = t * 2 - 1) * t * ((s4 + 1) * t - s4) + 0.5; // 回弹减速然后加速
            case EasingType.elasticIn:
                return t === 0 ? 0 : t === 1 ? 1 : -Math.pow(2, 10 * (t - 1)) * Math.sin((t - 1.1) * 5 * Math.PI); // 弹性加速
            case EasingType.elasticOut:
                return t === 0 ? 0 : t === 1 ? 1 : Math.pow(2, -10 * t) * Math.sin((t - 0.1) * 5 * Math.PI) + 1; // 弹性减速
            case EasingType.elasticInOut:
                if (t === 0) return 0;
                if (t === 1) return 1;
                if (t < 0.5) {
                    return -0.5 * Math.pow(2, 20 * t - 10) * Math.sin((20 * t - 11.125) * Math.PI / 2.25);
                } else {
                    return 0.5 * Math.pow(2, -20 * t + 10) * Math.sin((20 * t - 11.125) * Math.PI / 2.25) + 1;
                } // 弹性加速然后减速
            case EasingType.elasticOutIn:
                if (t === 0) return 0;
                if (t === 1) return 1;
                if (t < 0.5) {
                    return 0.5 * Math.pow(2, -20 * t) * Math.sin((20 * t - 0.5) * 5 * Math.PI) + 0.5;
                } else {
                    return 0.5 * -Math.pow(2, 10 * (2 * t - 1.5)) * Math.sin((2 * t - 1.6) * 5 * Math.PI) + 0.5;
                } // 弹性减速然后加速
            case EasingType.bounceIn:
                return 1 - this._bounceOut(1 - t); // 弹跳加速
            case EasingType.bounceOut:
                return this._bounceOut(t); // 弹跳减速
            case EasingType.bounceInOut:
                return t < 0.5
                    ? (1 - this._bounceOut(1 - 2 * t)) / 2
                    : (1 + this._bounceOut(2 * t - 1)) / 2; // 弹跳加速然后减速
            case EasingType.bounceOutIn:
                return t < 0.5
                    ? this._bounceOut(t * 2) / 2
                    : (1 - this._bounceOut(2 - 2 * t)) / 2 + 0.5; // 弹跳减速然后加速
            default:
                return t; // 默认线性
        }
    }

    /**
     * 辅助函数：弹跳减速效果
     */
    private _bounceOut(t: number): number {
        if (t < 1 / 2.75) {
            return 7.5625 * t * t;
        } else if (t < 2 / 2.75) {
            return 7.5625 * (t -= 1.5 / 2.75) * t + 0.75;
        } else if (t < 2.5 / 2.75) {
            return 7.5625 * (t -= 2.25 / 2.75) * t + 0.9375;
        } else {
            return 7.5625 * (t -= 2.625 / 2.75) * t + 0.984375;
        }
    }

    /**
     * 初始化Graphics组件
     */
    private _initGraphics(): void {
        // 为每个MovingTarget实例创建唯一的轨迹节点名称，避免多个实例共享同一个轨迹节点
        const uniqueNodeName = `TrajectoryGraphics_${this.node.uuid}`;

        // 尝试查找已存在的轨迹节点（基于唯一ID）
        let graphicsNode = this.node.parent?.getChildByName(uniqueNodeName);

        // 如果不存在，则创建新的轨迹节点
        if (!graphicsNode) {
            graphicsNode = new Node(uniqueNodeName);
            // 初始时先添加到场景中，但不设置父节点，会在_drawTrajectory中设置
            if (this.node.parent) {
                this.node.parent.addChild(graphicsNode);
            } else {
                this.node.addChild(graphicsNode);
            }
        }

        // 获取或添加Graphics组件到节点
        this._graphics = graphicsNode.getComponent(Graphics);
        if (!this._graphics) {
            this._graphics = graphicsNode.addComponent(Graphics);
        }
    }

    /**
     * 清除轨迹
     */
    public clearTrajectory(): void {
        if (!this._graphics) return;
        // 清除之前的轨迹
        this._graphics.clear();
    }

    /**
     * 绘制轨迹
     */
    private _drawTrajectory(): void {
        if (!this.showTrajectory) return;

        if (!this._graphics) return;
        // 清除之前的轨迹
        this._graphics.clear();

        // 设置轨迹样式
        this._graphics.lineWidth = this.trajectoryWidth;
        this._graphics.strokeColor = this.trajectoryColor;

        // 获取Graphics所在节点
        const graphicsNode = this._graphics.node;

        // 将Graphics节点设置为与主节点的父节点相同，确保轨迹在世界坐标系中绘制
        if (this.node.parent) {
            graphicsNode.parent = this.node.parent;

            // 移动到起点（世界坐标系中的实际位置）
            this._graphics.moveTo(this._startPoint.x, this._startPoint.y);

            // 直接使用控制点和终点的世界坐标绘制贝塞尔曲线
            this._graphics.quadraticCurveTo(
                this._controlPoint.x, this._controlPoint.y,
                this._endPoint.x, this._endPoint.y
            );
        }

        // 应用绘制
        this._graphics.stroke();
    }

    /**
     * 平滑角度插值，确保选择最短路径旋转
     * @param currentAngle 当前角度
     * @param targetAngle 目标角度
     * @param smoothFactor 平滑系数（0-1），值越小越平滑
     * @returns 插值后的新角度
     */
    private _smoothAngle(currentAngle: number, targetAngle: number, smoothFactor: number): number {
        // 确保平滑系数在有效范围内
        smoothFactor = Math.max(0.001, Math.min(1, smoothFactor));

        // 标准化角度到 0-360 范围
        const normalizeAngle = (angle: number): number => {
            angle = angle % 360;
            return angle < 0 ? angle + 360 : angle;
        };

        // 标准化当前角度和目标角度
        const normCurrent = normalizeAngle(currentAngle);
        const normTarget = normalizeAngle(targetAngle);

        // 计算最短路径旋转方向
        let delta = normTarget - normCurrent;

        // 如果角度差大于180度，选择另一个方向旋转（最短路径）
        if (delta > 180) {
            delta -= 360;
        } else if (delta < -180) {
            delta += 360;
        }

        // 应用平滑系数进行插值
        return currentAngle + delta * smoothFactor;
    }
}



